package cn.cutie.clot.mq.store;

import cn.cutie.clot.mq.model.ClotMessage;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.Getter;
import lombok.SneakyThrows;

import java.io.File;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * @Description:
 * @Author: Cutie
 * @CreateDate: 2024/7/15 23:09
 * @Version: 0.0.1
 */
public class MessageStore {

    private String topic;

    public static final int LENGTH = 1024 * 1024;

    public MessageStore(String topic) {
        this.topic = topic;
    }

    @Getter
    MappedByteBuffer mappedByteBuffer = null;

    @SneakyThrows
    public void init() {
        File file = new File(topic + ".dat");
        if (!file.exists()){
            file.createNewFile();
        }

        Path path = Paths.get(file.getAbsolutePath());
        // 文件的内存映射
        FileChannel fileChannel = (FileChannel) Files.newByteChannel(path, StandardOpenOption.READ, StandardOpenOption.WRITE);
        mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1024 * 100);

        // TODO: 2024/7/16 判断是否有之前的数据，如果有的话，则offset置为当前的长度
        // 判断是否有数据
        // 读取前10位，转为int，看是不是大于0，大于0说明有数据，往后翻，继续读，直到找到数据结尾
        // 找到数据结尾
//        mappedByteBuffer.position(initPos);

        // TODO: 2024/7/16 大于10M，使用多个数据文件的list来管理持久化数据
        // 需要创建第二个数据文件，怎么管理多个数据文件
    }

    public int write(ClotMessage<?> clotMessage) {
        System.out.println("write position: " + mappedByteBuffer.position());
        String msg = JSON.toJSONString(clotMessage);
        int position = mappedByteBuffer.position();
        int length = msg.getBytes(StandardCharsets.UTF_8).length;
        // 新增消息长度 start
//        String format = String.format("%010d", length);
//        msg = format + msg;
//        length += 10;
        // 新增消息长度 end
        Indexer.addEntry(topic, position, length);
        mappedByteBuffer.put(Charset.forName("UTF-8").encode(msg));
        return position;
    }

    public int pos(){
        return mappedByteBuffer.position();
    }

    public ClotMessage<?> read(int offset) {
        ByteBuffer readOnlyBuffer = mappedByteBuffer.asReadOnlyBuffer();
        Indexer.Entry entry = Indexer.getEntry(topic, offset);
        readOnlyBuffer.position(entry.getOffset());
        int len = entry.getLength();
        byte[] bytes = new byte[len];
        readOnlyBuffer.get(bytes, 0, len);
        String json = new String(bytes, StandardCharsets.UTF_8);
        System.out.println("read only : " + json);
        ClotMessage<String> message = JSON.parseObject(json, new TypeReference<ClotMessage<String>>() {
        });
//        System.out.println("message.getBody(): " + message.getBody());
        return message;
    }
}
